<?php
/** 订单 */
namespace app\api\service;

use app\api\model\Order as OrderModel;
use app\api\model\Product;
use app\api\model\UserAddress;
use app\api\model\OrderProduct;
use app\lib\exception\OrderException;
use app\lib\exception\UserException;
use Exception;
use think\Db;

class Order{
    protected $oProducts;//订单的商品列表=客户传递的products参数
    protected $products;//真实的商品信息（包括库存量）
    protected $uid;

    public function place($uid,$oProducts){
        //oProducts和Products做对比
        //从数据库查询Products
        $this->oProducts=$oProducts;
        $this->products=$this->getProductsByOrder($oProducts);
        $this->uid=$uid;
        $status=$this->getOrderStatus();
        if(!$status['pass']){//检查库存量是否通过
            $status['order_id']=-1;
            return $status;
        }
         
        //开始创建订单
        $orderSnap=$this->snapOrder($status);
        $order=$this->createOrder($orderSnap);
        $order['pass']=true;
        return $order;
    }

    //7、把订单信息写入数据库
    private function createOrder($snap){
        Db::startTrans();
        try{
            $orderNo=$this->makeOrderNo();
            $order=new OrderModel();
            $order->user_id=$this->uid;
            $order->order_no=$orderNo;
            $order->total_price=$snap['orderPrice'];//$snap['orderPrice']
            $order->total_count=$snap['totalCount'];
            $order->snap_img=$snap['snapImg'];
            $order->snap_name=$snap['snapName'];
            $order->snap_address=$snap['snapAddress'];
            $order->snap_items=json_encode($snap['pStatus']);
    
            $order->save();
            $orderID=$order->id;
            $create_time=$order->create_time;

            foreach($this->oProducts as &$p){
                $p['order_id']=$orderID;
            }
            $orderProduct=new OrderProduct();
            $orderProduct->saveAll($this->oProducts);
            Db::commit();
            return[
                'order_no'=>$orderNo,
                'order_id'=>$orderID,
                'create_time'=>$create_time
            ];
        }catch(Exception $ex){
            Db::rollback();
            throw $ex;
        }
    }

    //6、创建订单号
    public static function makeOrderNo(){
        $yCode=array('A','B','C','D','E','F','G','H','I','J');
        $orderSn=$yCode[intval(date('Y'))-2019].strtoupper(dechex(date('m'))).date(
            'd').substr(time(),-5).substr(microtime(),2,5).sprintf(
            '%02d',rand(0,99));
        return $orderSn;
    }

    //4、生成订单快照
    private function snapOrder($status){
        $snap=[
            'orderPrice'=>0,
            'totalCount'=>0,
            'pStatus'=>[],
            'snapAddress'=>null,
            'snapName'=>'',
            'snapImg'=>''
        ];

        $snap['orderPrice']=$status['orderPrice'];
        $snap['totalCount']=$status['totalCount'];
        $snap['pStatus']=$status['pStatusArray'];
        $snap['snapAddress']=json_encode($this->getUserAddress());
        $snap['snapName']=$this->products[0]['name'];
        $snap['snapImg']=$this->products[0]['main_img_url'];

        if(count($this->products)>1){
            $snap['snapName'].='等';
        }
        return $snap;
    }

    //5、获取用户地址
    private function getUserAddress(){
        $userAddress=UserAddress::where('user_id','=',$this->uid)
            ->find();
        if(!$userAddress){
            throw new UserException([
                'msg'=>'用户收货地址不存在，下单失败',
                'errorCode'=>60001,
            ]);
        }
        return $userAddress->toArray();
    }

    //3、获取订单状态（做对比）
    private function getOrderStatus(){
        $status=[
            'pass'=>true,
            'orderPrice'=>0,
            'totalCount'=>0,
            'pStatusArray'=>[]
        ];

        foreach($this->oProducts as $oProduct){
            $pStatus=$this->getProductStatus(
                $oProduct['product_id'],$oProduct['count'],$this->products);
            if(!$pStatus['haveStock']){
                $status['pass']=false;
            }
            $status['orderPrice']+=$pStatus['totalPrice'];
            $status['totalCount']+=$pStatus['count'];
            array_push($status['pStatusArray'],$pStatus);
        }
        return $status;
       
    }

    //对外方法提供检查库存
    public function checkOrderStock($orderID){
        $oProducts=OrderProduct::where('order_id','=',$orderID)
            ->select();
            $this->oProducts=$oProducts;
            $this->products=$this->getProductsByOrder($oProducts);
            $status=$this->getOrderStatus();
            return $status;
    }

    //2、获取商品状态
    private function getProductStatus($oPIDs,$oCount,$products){
        $pIndex=-1;
        $pStatus=[
            'id'=>null,
            'haveStock'=>false,
            'count'=>0,
            'name'=>'',
            'totalPrice'=>0
        ];

        for($i=0;$i<count($products);$i++){
            if($oPIDs==$products[$i]['id']){
                $pIndex=$i;
            }
        }
        if($pIndex==-1){
            //客户端传递的product_id有可能根本不存在
            throw new OrderException([
                'msg'=>'id为'.$oPIDs.'商品不存在，创建订单失败'
            ]);
        }else{
            $product=$products[$pIndex];
            $pStatus['id']=$product['id'];
            $pStatus['name']=$product['name'];
            $pStatus['count']=$oCount;
            $pStatus['totalPrice']=$product['price']*$oCount;
            if($product['stock']-$oCount>=0){
                $pStatus['haveStock']=true;
            }
        }
        return $pStatus;
    }

    //1、根据订单信息查找真实的商品信息（获取$products）
    private function getProductsByOrder($oProducts){
        $oPIDs=[];//$oProducts的所有ID
        foreach($oProducts as $item){
            array_push($oPIDs,$item['product_id']); //循环查询id
        }
        $products=Product::all($oPIDs)
            ->visible(['id','price','stock','name','main_img_url'])
            ->toArray();
        return $products;
    }
}